
pysvn=__import__('pysvn')
##@author Alessio Di Pietro
#@author Irene Scionti
#@brief An svn client
class svnClient(object):
    '''
    Manage svn server
    '''
    ## @brief Short description
    # @param wcopy path to working copy
    # @param host server ip/hostame
    # @param path repository path 
    # @param svnUser svn server username
    # @param svnPassword svn server password
    def __init__(self,wcopy,host,path,svnUser,svnPassword):
        '''
        Constructor
        '''
        
        self.__client= pysvn.Client();
        self.__host=host;
        self.__path=path;
        self.__svnWorkingCopy=wcopy;
        self.__svnUser=svnUser;
        self.__svnPassword=svnPassword;
        self.__client.callback_get_login = self.get_login;
        self.__client.set_store_passwords(False)
    '''
    Setter Getter methods
    '''
    ## @brief Set working copy path
    # @param wcopy path to working copy 
    def setWcopy(self,wcopy):
        self.svnWorkingCopy=wcopy
    ## @brief Set repository path
    # @param path to local repository 
    def setRepoPath(self,path):
        self.path=path
    ## @bried Get working copy path
    # @return actual working copy path   
    def getWcopy(self):
        return self.__svnWorkingCopy;
    ## @brief Set repository url
    # @param url repository url
    def setURL(self,url):
        self.__host=url;
    '''
    Working copy methods
    '''
    ## @brief Callback for svnserve authentication
    # @param realm realm of svn repository
    # @param username username used for login
    # @param may_save true for saving locally passwords, false otherwise 
    def get_login(self,realm, username, may_save):
        return True, self.__svnUser, self.__svnPassword, False
    
    ## @brief svn co
    # @param revision revision number to be extracted or 'head' for head revision.
    def checkout(self,revision):
        
        '''
        Check out a working copy
        '''
        
        if revision=='head':
            #check out the current version of the pysvn project
            self.__client.checkout('svn://'+self.__host,self.__svnWorkingCopy)
            

        else:
            #check out revision n of the pysvn project
            self.__client.checkout('svn://'+self.__host,
                                   self.__svnWorkingCopy,
                                   revision=pysvn.Revision(pysvn.opt_revision_kind.number, revision))
    ## @brief svn add
    # @param file file to be addedd
    def add(self,file,message=None):
        '''
        Add a file or directory to the repository (assumed in the working-copy)
        '''
        #schedule the addition; 
        #  the working copy will now track the file as a scheduled change
        self.__client.add(self.__svnWorkingCopy+file)
    ## @brief svn update
    # @param revision revision number to be extracted or 'head' for head revision
    def update(self,revision):
        '''
        Update a working copy to revision number or head
        '''
        if revision=='head':
            self.__client.update(self.__svnWorkingCopy,revision=pysvn.Revision(pysvn.opt_revision_kind.head ))
        else:
            self.__client.update(self.__svnWorkingCopy,revision=pysvn.Revision(pysvn.opt_revision_kind.number,revision ))
    
    ## @brief svn ci
    # @param message commit message 
    def commit(self,message):
        '''
        Commit changes to the repository
        '''
        # checkin the change with a log message
        self.__client.checkin([self.__svnWorkingCopy], message)
    ## @bried svn revert
    # @param file file to be reverted
    def revert(self,file):
        '''
        Discard changes in the working copy
        '''
        #discard the edits
        self.__client.revert(self.__svnWorkingCopy+file)
    
    ## @brief svn mv
    # @param sfile source file
    # @param dfile destination file
    def move(self,sfile,dfile):
        '''
        Rename or move a file
        '''
        #rename the file client side 
        self.__client.move(self.__svnWorkingCopy+sfile, self.__svnWorkingCopy+dfile)
    
    ## @brief svn rm
    # @param file file to be removed 
    def remove(self,file):
        '''
        Remove a file or directory from the repository
        '''
        #schedule the removal; 
        #  the file will be removed from the working copy
        self.__client.remove(self.__svnWorkingCopy+file)
    
    ## @brief svn info
    # @param path file or directory to check
    # @param depth recursion depth 
    # @return list of changed files in path "path"
    def status(self,path,depth):
        '''
        Determine pending changes
        '''
        changes = self.__client.status(self.__svnWorkingCopy+path,depth=depth)
        print 'files that have changed:'
        changed=[f for f in changes if f.text_status == pysvn.wc_status_kind.modified]
        return changed
    
    def log(self,file_path,revision):
        '''
        Executes svn log
        '''
        if revision=='head':
            file_log=self.__client.log("svn://"+self.__host+file_path,peg_revision=pysvn.Revision(pysvn.opt_revision_kind.head))
        else:
            #print "svn://"+self.__host+file_path+",revision=",pysvn.Revision(pysvn.opt_revision_kind.number,revision )
            
            file_log=self.__client.log("svn://"+self.__host+file_path,revision_start=pysvn.Revision(pysvn.opt_revision_kind.number,int(revision)),peg_revision=pysvn.Revision(pysvn.opt_revision_kind.number,int(revision)))
        return file_log
    ## @brief svn diff
    # @param file file to be differed
    # @param prev_revision revision of the other file
    # @return a text file representing the diff  
    def diff(self,file,prev_revision=''):
        '''
        Generating a diff or patch of file with his previous revision
        '''
        if prev_revision!='':
            diff_text = self.__client.diff('/tmp/diff_prefix', url_or_path=self.__svnWorkingCopy+file,
                                       revision1=pysvn.Revision( pysvn.opt_revision_kind.number, prev_revision ))
        else:
            diff_text = self.__client.diff('/tmp/diff_prefix', url_or_path=self.__svnWorkingCopy+file,
                                       revision1=pysvn.Revision(pysvn.opt_revision_kind.previous))
        return diff_text
    

    def info(self,path_from_wcopy):
        '''
        Determining the repository URL
        '''
      
        self.entry = self.__client.info(self.__svnWorkingCopy+path_from_wcopy);
        #print 'Url:',self.entry.url;
        return self.entry
    
    '''
    Repository Methods
    '''
    def repoList(self):
        '''
        List the contents of a repository directory
        '''
        
        self.entry_list = self.__client.ls(self.__svnWorkingCopy);
        print self.entry_list
    
    ## @brief svn cat
    #  @param file_path file to be catted
    #  @param revision file revision number or 'head' for head revision
    #  @return file content 
    def repoCat(self,file_path,revision):
        '''
        Get the contents of a file from the repository
        '''
        if revision=='head':
            file_content=self.__client.cat("svn://"+self.__host+file_path,revision=pysvn.Revision(pysvn.opt_revision_kind.head ))
        else:
            #print "svn://"+self.__host+file_path+",revision=",pysvn.Revision(pysvn.opt_revision_kind.number,revision )
            file_content=self.__client.cat("svn://"+self.__host+file_path,revision=pysvn.Revision(pysvn.opt_revision_kind.number,revision ))
            
        return file_content

    def get_log_message(self):
        return True, self.log_message

    def repoBranch(self, message, tag_name):
        '''
        Create a branch or tag
        '''
        self.log_message = message;
    
    
        self.__client.callback_get_log_message = self.get_log_message
        self.__client.copy('http://svnrepo.com/svn/trunk', 'http://svnrepo.com/svn/tag/%s' % tag_name )

    def repoMove(self,vecchio_file,nuovo_file):
        '''
        Move or rename files in the repository        
        '''
        self.__client.move(self.__svnWorkingCopy+vecchio_file,self.__svnWorkingCopy+nuovo_file );

    def repoLock(self,nome_file,reason):
        '''
        Lock a file       
        '''
        self.__client.lock(self.__svnWorkingCopy+nome_file, reason);
       
    def repoUnLock(self,nome_file):
        '''
        Unlock a file        
        '''
        self.client.unlock(self.__svnWorkingCopy+nome_file )

    def repoTestLock(self,path):
        '''
        Test for a locked file        
        '''
        self.all_entries = self.__client.info2( self.__svnWorkingCopy+path, recurse=False )
        for self.path, info in self.all_entries:
            if info['lock']:
                if info['lock']['token'] != '':
                    print '%s is locked' % self.path
                print info['lock']['comment']